using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using lch_grass;
#if UNITY_EDITOR
using UnityEditor;
#endif

/// <summary>
/// 编辑器类型枚举
/// </summary>
public enum OCEditorType
{
    EDITOR,     // 编辑模式
    DATA_ARRAY, // 数据数组模式
    DATA_TREE,  // 数据树模式
}
[System.Serializable]
public struct RenderData
{
    public Mesh mesh;
    public Material mat;
    public int subMeshIndex;
    public bool far ;
}

public enum OCTreeDebug
{
    [EnumAttirbute("所有节点")]
    ALL,
    [EnumAttirbute("最终节点")]
    FINAL_NODE,
}

/// <summary>
/// 八叉树渲染组件
/// 用于管理LOD设置和对象数据转换
/// </summary>
[ExecuteInEditMode]
public class OCTreeRender : MonoBehaviour
{
    public GameObject target;
    [Label("Log组件", "hasLod")]
    [NotEditable]
    public LODGroup group;
    [Label("远处lod取第几层", "hasLod")]
    [NotEditable]
    public int level1 = 1;
    [Label("lod2 出现的距离", "hasLod")]
    [Range(5f, 25f)]
    public float lod1Distance = 15f;
    [Range(0f,1000f)]
    public float cutDistance = 180f;

    [Label("数据")]
    [NotEditable]
    public RenderData [] renderData  ;

    [Label("绘制的相机")]
    public Camera renderCamera;

    [HideInInspector]
    public List<Matrix4x4> istDatas = new List<Matrix4x4>();
    [HideInInspector]
    public bool hasLod = false;
    [HideInInspector]
    public OCEditorType isEditModel = OCEditorType.EDITOR;

    [Label("数据数量")]
    [NotEditable]
    public int DataCount = 0;

    public LchOcTree tree;

    [CNEnum(typeof(OCTreeDebug), "调试模型")]
    public OCTreeDebug debugModel = OCTreeDebug.FINAL_NODE;
    [Label("选中后显示树")]
    public bool showOnSelect = false;

    static Plane[] planes = new Plane[6];
    static Plane[] nearPlanes = new Plane[6];
    private void OnEnable()
    {
        InitRender();
        FillTree();
    }
    void InitRender()
    {
        if (group!=null)
        {
            var gs = group.GetLODs();
            List<RenderData> datas = new List<RenderData>();
            FillData(gs, 0, datas);
            FillData(gs, level1, datas);
            renderData = datas.ToArray();
        }
        else
        {
            List<RenderData> datas = new List<RenderData>();
            FillData(target, datas);
            renderData = datas.ToArray();

        }
        
    }

    private void FillData(LOD[] gs, int v, List<RenderData> datas)
    {
        // 确保级别索引在有效范围内
        if (v < 0 || v >= gs.Length)
            return;

        // 获取指定级别的LOD
        LOD lod = gs[v];

        // 遍历该级别下的所有渲染器
        foreach (Renderer renderer in lod.renderers)
        {
            // 确保渲染器不为空
            if (renderer == null)
                continue;

            Mesh mesh = renderer.GetComponent<MeshFilter>()?.sharedMesh;
            if (null != mesh)
            {
                var mats = renderer.sharedMaterials;
                for (int i = 0; i < mats.Length; i++)
                {
                    var mat = mats[i];
                    if (null != mat)
                    {
                        // 创建并填充渲染数据
                        RenderData data = new RenderData();
                        data.far = v > 0;
                        data.mesh = mesh;
                        data.subMeshIndex = i;
                        data.mat = mat;

                        datas.Add(data);
                    }
                }
            }
            
            
        }
        // 按材质的渲染队列排序（从小到大）
        datas.Sort((a, b) => a.mat.renderQueue.CompareTo(b.mat.renderQueue));
    }



    private void FillData(GameObject g, List<RenderData> datas)
    {
        // 确保级别索引在有效范围内
        if (g ==null)
            return;


        var rs = g.GetComponentsInChildren<MeshRenderer>();
        // 遍历该级别下的所有渲染器
        foreach (MeshRenderer renderer in rs)
        {
            // 确保渲染器不为空
            if (renderer == null)
                continue;

            Mesh mesh = renderer.GetComponent<MeshFilter>()?.sharedMesh;
            if (null != mesh)
            {
                var mats = renderer.sharedMaterials;
                for (int i = 0; i < mats.Length; i++)
                {
                    var mat = mats[i];
                    if (null != mat)
                    {
                        // 创建并填充渲染数据
                        RenderData data = new RenderData();
                        data.far = false;
                        data.mesh = mesh;
                        data.subMeshIndex = i;
                        data.mat = mat;

                        datas.Add(data);
                    }
                }
            }
        }
        // 按材质的渲染队列排序（从小到大）
        datas.Sort((a, b) => a.mat.renderQueue.CompareTo(b.mat.renderQueue));
    }


    /// <summary>
    /// 每帧更新
    /// </summary>
    private void LateUpdate()
    {
#if UNITY_EDITOR
        if (hasLod)
        {
            // 确保LOD级别不超过可用级别
            level1 = Math.Min(group.lodCount - 1, level1);
        }
        if (null == renderCamera)
        {
            renderCamera = Camera.main;
        }
#endif
        if (null != renderCamera)
        {
            Render();
        }
    }
    LchOcTreeNode[] nodes = new LchOcTreeNode[100];
    int nodesCount = 0;

    LchOcTreeNode[] nodesFar = new LchOcTreeNode[100];
    int nodesFarCount = 0;

    static Matrix4x4[] temp = new Matrix4x4[1000];
    static int tempCount = 0;

    private void DrawInstancedBatches(Mesh mesh, Material mat,int subMeshIndex, LchOcTreeNode[] nodeArray, int nodeCount)
    {
        tempCount = 0;

        for (int j = 0; j < nodeCount; j++)
        {
            var n = nodeArray[j];
            int countToAdd = n.objs.Count;

            // 先判断整体是否会溢出temp数组
            if (tempCount + countToAdd > 1000)
            {
                // 先绘制当前积攒的
                if (tempCount > 0)
                {
                    Graphics.DrawMeshInstanced(mesh, 0, mat, temp, tempCount);
                    tempCount = 0;
                }

                // 如果单个节点obj数量大于1000，分批绘制
                if (countToAdd > 1000)
                {
                    int index = 0;
                    while (index < countToAdd)
                    {
                        int batchSize = Mathf.Min(1000, countToAdd - index);
                        for (int k = 0; k < batchSize; k++)
                        {
                            temp[k] = n.objs[index + k].mat;
                        }
                        Graphics.DrawMeshInstanced(mesh, subMeshIndex, mat, temp, batchSize);
                        index += batchSize;
                    }
                }
                else
                {
                    // 直接加入temp，准备下一次绘制
                    for (int k = 0; k < countToAdd; k++)
                    {
                        temp[tempCount++] = n.objs[k].mat;
                    }
                }
            }
            else
            {
                // 直接加入temp，不溢出
                for (int k = 0; k < countToAdd; k++)
                {
                    temp[tempCount++] = n.objs[k].mat;
                }
            }
        }

        // 绘制剩余实例
        if (tempCount > 0)
        {
            Graphics.DrawMeshInstanced(mesh, subMeshIndex, mat, temp, tempCount);
            tempCount = 0;
        }
    }

    private void Render()
    {
        if (null == tree|| renderData==null)
        {
            OnEnable();
        }
        float oldFar = renderCamera.farClipPlane;
        renderCamera.farClipPlane = cutDistance;
        GeometryUtility.CalculateFrustumPlanes(renderCamera, planes);

        if (hasLod)
        {
            renderCamera.farClipPlane = lod1Distance;
            GeometryUtility.CalculateFrustumPlanes(renderCamera, nearPlanes);

            tree.GetInBounds(planes, nearPlanes[5], ref nodes, ref nodesCount, ref nodesFar, ref nodesFarCount);
        }
        else
        {
            nodesFarCount = 0;

 
            tree.GetInBounds(planes, ref nodes, ref nodesCount);
        }

        renderCamera.farClipPlane = oldFar;

        // 逐条渲染数据循环
        for (int i = 0; i < renderData.Length; i++)
        {
            var rd = renderData[i];
            var mesh = rd.mesh;
            var mat = rd.mat;
            mat.enableInstancing = true;

            tempCount = 0;

            if (rd.far)
            {
                DrawInstancedBatches(rd.mesh, rd.mat,rd.subMeshIndex, nodesFar, nodesFarCount);
            }
            else
            {
                DrawInstancedBatches(rd.mesh, rd.mat, rd.subMeshIndex, nodes, nodesCount);
            }
        }
    }
    void FillTree()
    {
        if (Application.isPlaying)
        {
            if (istDatas.Count == 0)
                return;
        }
        tree = new LchOcTree();

        for (int i = 0; i < istDatas.Count; i++)
        {
            Matrix4x4 mat = istDatas[i];
            tree.AddObj(new LchOcTreeObj(tree.GetNewId(), mat));
        }
        if (Application.isPlaying)
        {
            istDatas.Clear();
        }
       // Debug.Log(istDatas.Count.ToString() + " new id " + tree.GetNewId());

    }

#if UNITY_EDITOR
    /// <summary>
    /// 获取物体的预制体源对象
    /// </summary>
    /// <param name="instance">实例对象</param>
    /// <returns>预制体源对象</returns>
    public static GameObject GetPrefabSource(GameObject instance)
    {
        if (instance == null) return null;
        // 获取预制体实例的根对象
        GameObject prefabRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(instance);
        if (prefabRoot == null) return null;

        // 获取源预制体
        return PrefabUtility.GetCorrespondingObjectFromSource(prefabRoot);
    }

    /// <summary>
    /// 转换为数据数组模式
    /// 收集所有匹配目标预制体的子对象并保存其变换矩阵
    /// </summary>
    public void changeToDataArray()
    {
        if (null == target)
        {
           
            return;
        }
             

        string path = AssetDatabase.GetAssetPath(target);
        if (null == path || path.Length == 0)
        {
            GameObject g = GetPrefabSource(target);
            target = g;
            path = AssetDatabase.GetAssetPath(g);
        }

        List<GameObject> founds = new List<GameObject>();
        int childCount = transform.childCount;

        // 显示进度条并处理所有子对象
        for (int i = 0; i < childCount; i++)
        {
            // 更新进度条
            float progress = (float)i / childCount;
            if (EditorUtility.DisplayCancelableProgressBar("转换数据",
                $"正在处理子对象 {i + 1}/{childCount}", progress))
            {
                // 用户取消操作
                EditorUtility.ClearProgressBar();
                return;
            }

            GameObject g = transform.GetChild(i).gameObject;
            GameObject g0 = GetPrefabSource(g);
            if (g0 == target)
            {
                founds.Add(g);
                istDatas.Add(g.transform.localToWorldMatrix);
            }
        }

        // 清除进度条
        EditorUtility.ClearProgressBar();

        // 显示第二个进度条以销毁对象
        int foundCount = founds.Count;
        for (int i = 0; i < foundCount; i++)
        {
            float progress = (float)i / foundCount;
            if (EditorUtility.DisplayCancelableProgressBar("销毁对象",
                $"正在销毁匹配对象 {i + 1}/{foundCount}", progress))
            {
                EditorUtility.ClearProgressBar();
                return;
            }

            GameObject g = founds[i];
            GameObject.DestroyImmediate(g, true);
        }
        DataCount = istDatas.Count;
        // 清除进度条并标记对象为已修改
        EditorUtility.ClearProgressBar();
        EditorUtility.SetDirty(this.gameObject);
        InitRender();
        FillTree();
    }
    private void OnDrawGizmos()
    {
        if (!showOnSelect)
        {
            DrawDebug();
        }
    }
    private void OnDrawGizmosSelected()
    {
        if (showOnSelect)
        {
            DrawDebug();
        }
    }
    void DrawDebug()
    {
        switch (debugModel)
        {
            case OCTreeDebug.ALL:
                {
                    if (null != tree)
                    {
                        tree.Draw();
                    }
                }
                break;
            case OCTreeDebug.FINAL_NODE:
                {
                    for (int i = 0; i < nodesCount; i++)
                    {
                        var n = nodes[i];
                        n.Draw(Color.green);
                    }

                    for (int i = 0; i < nodesFarCount; i++)
                    {
                        var n = nodesFar[i];
                        n.Draw(Color.yellow);
                    }
                }
                break;
        }
    }
    
    
    /// <summary>
    /// 更新目标对象的LOD设置
    /// </summary>
    public void UpdateTarget()
    {
        if (null == target)
        {
            // 目标为空，禁用LOD功能
            hasLod = false;
        }
        else
        {
            target = GetPrefabSource(target);
            // 获取目标对象的LOD组件
            group = target.GetComponentInChildren<LODGroup>();
            if (group != null)
            {
                level1 = group.lodCount - 1;

               
                hasLod = true;
            }
            else
            {
                renderData = new RenderData[0];
                hasLod = false;
            }
            
        }
        
        EditorUtility.ClearProgressBar();
        EditorUtility.SetDirty(this.gameObject);
    }

    
    

    public void dataToPerfabs()
    {
        if (null == target)
        {
            // 目标为空，禁用LOD功能
            hasLod = false;
        }
        for (int i = 0; i < istDatas.Count; i++)
        {
            Matrix4x4 mat = istDatas[i];
            GameObject g = (GameObject)PrefabUtility.InstantiatePrefab(target);

            if (g != null)
            {
                // 应用矩阵变换
                g.transform.position = mat.GetColumn(3);
                g.transform.rotation = Quaternion.LookRotation(mat.GetColumn(2), mat.GetColumn(1));
                g.transform.localScale = new Vector3(
                    mat.GetColumn(0).magnitude,
                    mat.GetColumn(1).magnitude,
                    mat.GetColumn(2).magnitude
                );

                // 设置父对象
                g.transform.SetParent(transform, true);
            }

        }
        istDatas.Clear();
        tree = null;
        EditorUtility.ClearProgressBar();
        EditorUtility.SetDirty(this.gameObject);
    }
#endif
}
